package com.daji.concurrency.cas_demo;

import java.util.concurrent.atomic.AtomicLong;

/**
 * CASCounter：使用CAS实现一个线程安全的计数器（没有使用Java提供的atom包，而是模拟了一个CAS操作）
 * Author: 老崔（参考资料：动力节点：http://www.bjpowernode.com/javathread/1211.html）
 *
 * CASCounterAtom：使用java的Atom类实现了老崔的计数器
 * Author：大吉
 */
public class CASSimulation {
    public static void main(String[] args) throws InterruptedException {
        CASCounter casCounter = new CASCounter();
        CASCounterAtom casCounterAtom = new CASCounterAtom();
        for (int i = 0; i < 100000; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    //打开这个注释，观察效果
                    //System.out.println(casCounter.incrementAndGet());
                    System.out.println(casCounterAtom.incrementAndGet2());
                }
            }).start();
        }
    }
}

//这只是模拟CAS的大致原理，操作系统中的CAS是基于内存比较！
//这只是模拟CAS的大致原理，操作系统中的CAS是基于内存比较！
//这只是模拟CAS的大致原理，操作系统中的CAS是基于内存比较！
class CASCounter{
    //使用volatile修饰value值,使线程可见
    volatile private long value = 6;

    public long getValue() {
        return value;
    }

    //定义comare and swap方法
    private boolean compareAndSwap(long expectedValue, long newValue){
        //如果当前value的值与期望的expectedVAlue值一样,就把当前的Value字段替换为newValue值
        synchronized (this){
            if ( value == expectedValue){   //执行到这一步，value已有可能被其它线程篡改（value有可能>expectedValue）
                value = newValue;   //到这里才让共享变量（volatile修饰）value自增1
                return true;
            }else {
                return false;       //value果真被其它线程篡改，返回 false
            }
        }
    }

    //自己 实现 一个 CAS
    public long incrementAndGet(){
        long oldvalue ;
        long newValue;
        do {        //如果条件不成立，重新读取value这个共享变量(回滚) 这是一种乐观思想
            oldvalue = value;
            newValue = oldvalue+1;
        }while ( !compareAndSwap(oldvalue, newValue) ); //如果条件不成立，重新读取value这个共享变量(回滚)
        return newValue;
    }

}


class CASCounterAtom{
    //使用volatile修饰value值,使线程可见
    volatile private AtomicLong value = new AtomicLong(6);

    public AtomicLong getValue() {
        return value;
    }

    //该方法同incrementAndGet一样，只不过是用java中的原子类实现了其操作
    public AtomicLong incrementAndGet2(){

        value.addAndGet(1); //以原子的方式自增1
        return value;
    }

}